package com.hxwm.hwdbtool.controller;

import com.hxwm.hwdbtool.controller.dialog.BaseDBConnectDialog;
import com.hxwm.hwdbtool.controller.dialog.MenuDBConnectDialog;
import com.hxwm.hwdbtool.core.DatabaseConnectionListener;
import com.hxwm.hwdbtool.core.HwLogAppender;
import com.hxwm.hwdbtool.entity.dbconnect.HwConnection;
import com.hxwm.hwdbtool.entity.dbconnect.HwDatabase;
import com.hxwm.hwdbtool.entity.dbconnect.HwDateSource;
import com.hxwm.hwdbtool.controller.menu.DataSourceNavMenuUI;
import com.hxwm.hwdbtool.service.DataBaseNavService;
import com.hxwm.hwdbtool.util.HwUtil;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import lombok.Data;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: hwdbtool
 * @ClassName controller
 * @description:
 * @author: hxwm
 * @create: 2024-04-26 20:05
 * @Version 1.0
 **/
@Data
public class HwDBToolController implements DatabaseConnectionListener {
    Logger logger = Logger.getLogger(HwDBToolController.class);
    //主菜单
    @FXML
    private AnchorPane mainContainer;
    @FXML
    private MenuBar mainMenuBar;
    @FXML
    private Menu fileMenu;
    @FXML
    private MenuItem openFile;
    @FXML
    private MenuItem saveFile;
    @FXML
    private MenuItem closeFile;
    @FXML
    private MenuItem importData;
    @FXML
    private MenuItem exportData;
    @FXML
    private Menu sqlEditMenu;
    @FXML
    private MenuItem newSqlEdit;
    @FXML
    private MenuItem openControl;
    @FXML
    private Menu databaseMenu;
    @FXML
    private MenuItem newConnect;
    @FXML
    private MenuItem closeConnect;
    @FXML
    private MenuItem driverManage;
    @FXML
    private Menu viewMenu;
    @FXML
    private MenuItem controlView;
    @FXML
    private Menu helpMenu;
    @FXML
    private MenuItem aboutInfo;

    //工具栏
    @FXML
    private Button newConnBtn;
    @FXML
    private MenuButton dbConnToolBar;
    @FXML
    private MenuItem dbMySQl;
    @FXML
    private MenuItem dbDB2LUW;
    @FXML
    private MenuItem dbSqlServer;
    @FXML
    private MenuItem dbOracle;
    @FXML
    private Button refreshConnBtn;
    @FXML
    private Button closeConnBtn;
    @FXML
    private Button sqlEidtBtn;
    @FXML
    private Button dataMigrationBtn;
    @FXML
    private Button sqlImportBtn;
    @FXML
    private Button sqlExportBtn;
    @FXML
    private Button searchBtn;

    //数据库导航栏
    @FXML
    private AnchorPane leftNavPane;
    @FXML
    private TabPane databaseNavPane;
    @FXML
    private Tab databaseNavTab;
    @FXML
    private TreeView databaseNavTreeView;
    @FXML
    private AnchorPane rightNavPane;
    @FXML
    private SplitPane rightNavSplitPane;
    @FXML
    private TabPane rightTopTabPane;
    @FXML
    private TabPane controlTabPane;
    @FXML
    private VBox controlLogVBox;
    @FXML
    private Tab controlLogTab;
    @FXML
    private Tab migrationLogTab;
    @FXML
    private Button clearLoggingBtn;
    @FXML
    private Button minControlPaneBtn;
    @FXML
    private Button maxControlPaneBtn;
    @FXML
    private ListView migrationLogListView;
    @FXML
    private ToolBar controlLogToolBar;
    @FXML
    private HBox newConnHBox;
    @FXML
    private Button dbConnToolBarButton;
    @FXML
    private ComboBox dataBaseListComboBox;
    @FXML
    private ComboBox selectedDbTableComboBox;

    private ContextMenu contextMenu;
    //主菜单数据库连接对话框
    private static final String mainAppDBConnectDialog = "/fxml/dbconnect/mainappdbconndialog.fxml";
    //数据库连接对话框
    private static final String dbConnectDialog = "/fxml/dbconnect/dbconnectdialog.fxml";
    //数据迁移tabpane
    private static final String dbmigrationTabPane = "/fxml/dbmigration/dbmigration.fxml";
    //Sql编辑器
    private static final String sqlEditorTabPane = "/fxml/sqleditor.fxml";
    private DbMigrationController controller;
    private Map<String,HwConnection> hwConnectionListMap;
    private HwDateSource currentHwDataSource;
    public void initialize() {
        // 初始化操作，可以在这里添加事件监听器等
        clearLoggingBtn.setOnAction(e->{
            TableView tableView = HwLogAppender.tableView;
            Platform.runLater(()->{
                Tab selectedItem = controlTabPane.getSelectionModel().getSelectedItem();
                if(!HwUtil.isNullOrEmpty(selectedItem)) {
                    String id = selectedItem.getId();
                    if ("controlLogTab".equals(id)) {
                        tableView.getItems().clear();
                        tableView.refresh();
                    } else if ("migrationLogTab".equals(id)) {
                        if(!controller.getImportBtn().isDisabled()) {
                            migrationLogListView.getItems().clear();
                        }
                    }
                }
            });
        });
        minControlPaneBtn.setOnAction(e->{
            rightNavSplitPane.setDividerPositions(1.0);
        });
        maxControlPaneBtn.setOnAction(e->{
            rightNavSplitPane.setDividerPositions(0.0);
        });

        //创建数据库连接的下拉菜单
        contextMenu = createContextMenu();

        dataBaseListComboBox.valueProperty().addListener((observable, oldValue, newValue) -> {
            if(!HwUtil.isNullOrEmpty(hwConnectionListMap)) {
                if (!"<N/A>".equals(newValue)) {
                    List<HwDatabase> hwDatabases = hwConnectionListMap.get(newValue).getDatabaseList();
                    for (HwDatabase hwDatabase : hwDatabases) {
                        selectedDbTableComboBox.getItems().add(hwDatabase.getDatabaseName());
                    }
                } else {
                    selectedDbTableComboBox.getItems().clear();
                }
            }
        });
        selectedDbTableComboBox.valueProperty().addListener((observable, oldValue, newValue)->{
            if(!HwUtil.isNullOrEmpty(newValue)) {
                String connectionName = (String) dataBaseListComboBox.getValue();
                HwConnection hwConnection = hwConnectionListMap.get(connectionName);
                HwDateSource hds = hwConnection.getHwDateSource();
                currentHwDataSource = new HwDateSource(hds.getDriverType(), hds.getDbIp(), hds.getDbPort(), (String) newValue, hds.getDbUser(), hds.getDbPassword());
            }else{
                currentHwDataSource = null;
            }
        });
        //设置菜单响应
        DataSourceNavMenuUI dataSourceNavMenuUI = new DataSourceNavMenuUI();
        databaseNavTreeView.setCellFactory(e -> {
            //每个 TreeCell 都会根据其对应的 TreeItem 设置不同的右键菜单
            TreeCell<String> cell = new TreeCell<String>() {
                @Override
                protected void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    if (empty) {
                        setText(null);
                        setContextMenu(null);
                    } else {
                        setText(item);
                        setContextMenu(dataSourceNavMenuUI.createContextMenu(this.getTreeItem()));
                    }
                }
            };
            return cell;
        });
    }

    private ContextMenu createContextMenu(){
        // 初始化ContextMenu
        ContextMenu contextMenu = new ContextMenu();
        ImageView iconMySQL = new ImageView(new Image(getClass().getResourceAsStream("/static/icon/driver/mysql.png")));
        iconMySQL.setFitWidth(15.0);
        iconMySQL.setFitHeight(15.0);
        MenuItem dbMySQl = new MenuItem("MySQL",iconMySQL);
        dbMySQl.setOnAction(event -> handleDbMySQl());

        ImageView iconDB2 = new ImageView(new Image(getClass().getResourceAsStream("/static/icon/driver/DB2.png")));
        iconDB2.setFitWidth(15.0);
        iconDB2.setFitHeight(15.0);
        MenuItem dbDB2LUW = new MenuItem("DB2 for LUW",iconDB2);
        dbDB2LUW.setOnAction(event -> handleDbDB2LUW());

        ImageView iconSqlServer = new ImageView(new Image(getClass().getResourceAsStream("/static/icon/driver/sqlserver.png")));
        iconSqlServer.setFitWidth(15.0);
        iconSqlServer.setFitHeight(15.0);
        MenuItem dbSqlServer = new MenuItem("SQL Server",iconSqlServer);
        dbSqlServer.setOnAction(event -> handleDbSqlServer());

        ImageView iconOracle = new ImageView(new Image(getClass().getResourceAsStream("/static/icon/driver/Oracle.png")));
        iconOracle.setFitWidth(15.0);
        iconOracle.setFitHeight(15.0);
        MenuItem dbOracle = new MenuItem("Oracle",iconOracle);
        dbOracle.setOnAction(event -> handleDbOracle());

        ImageView iconInformix = new ImageView(new Image(getClass().getResourceAsStream("/static/icon/driver/Informix.png")));
        iconInformix.setFitWidth(15.0);
        iconInformix.setFitHeight(15.0);
        MenuItem dbInformix = new MenuItem("Informix",iconOracle);
        dbInformix.setOnAction(event -> handleDbInformix());

        contextMenu.getItems().addAll(dbMySQl, dbDB2LUW, dbSqlServer, dbOracle,dbInformix);
        return contextMenu;
    }
    @FXML
    private void handleShowContextMenu(ActionEvent event){
        if (!contextMenu.isShowing()) {
            // 获取按钮的位置
            double x = newConnHBox.localToScreen(newConnHBox.getBoundsInLocal()).getMinX();
            double y = newConnHBox.localToScreen(newConnHBox.getBoundsInLocal()).getMaxY();
            contextMenu.show(dbConnToolBarButton, x, y);
        } else {
            contextMenu.hide();
        }
    }
    @FXML
    private void handleOpenFile() {
        // 处理打开文件菜单事件
    }

    @FXML
    private void handleSaveFile() {
        // 处理保存文件菜单事件
    }

    @FXML
    private void handleCloseFile() {
        // 处理关闭文件菜单事件
    }

    @FXML
    private void handleImportData() {
        // 处理导入数据菜单事件
    }

    @FXML
    private void handleExportData() {
        // 处理导出数据菜单事件
    }

    @FXML
    private void handleNewSqlEdit() {
        // 处理新建SQL编辑器菜单事件
        try {
            //创建tab
            Tab sqlEditorTab = new Tab();
            sqlEditorTab.setId("sqlEditorTab");
            sqlEditorTab.setText("* 新建脚本");

            //方案1：RichTextFX
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(sqlEditorTabPane));
            sqlEditorTab.setContent(fxmlLoader.load());
            SqlEditorController sqlEditorController = fxmlLoader.getController();
            sqlEditorController.setParentController(this);

            //方案2：WebView with CodeMirror
            //WebView webView = new WebView();
            //WebEngine webEngine = webView.getEngine();
            //webEngine.load(getClass().getResource("/static/html/editor.html").toExternalForm());
            //BorderPane root = new BorderPane(webView);
            //sqlEditorTab.setContent(root);

            //添加到父窗口
            rightTopTabPane.getTabs().add(sqlEditorTab);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @FXML
    private void handleOpenControl() {
        // 处理打开控制台菜单事件
    }

    @FXML
    private void handleNewConnect() {
        // 处理新建连接菜单事件
        showConnectDialog(mainAppDBConnectDialog,null);
    }

    @FXML
    private void handleCloseConnect() {
        // 处理断开连接菜单事件
    }

    @FXML
    private void handleDriverManage() {
        // 处理驱动管理菜单事件
    }

    @FXML
    private void handleControlView() {
        // 处理控制台显示菜单事件
        ObservableList<Tab> tabs = controlTabPane.getTabs();
        for (Tab tab : tabs) {
            if("controlLogTab".equals(tab.getId())){
                return;
            }
        }
        tabs.add(controlLogTab);
        rightNavSplitPane.setDividerPositions(0.6);
    }

    @FXML
    private void handleAboutInfo() {
        // 处理关于菜单事件
    }

    @FXML
    private void handleDbMySQl() {
        showConnectDialog(dbConnectDialog,"MySql");
    }

    @FXML
    private void handleDbDB2LUW() {
        // 处理数据库连接菜单事件
        showConnectDialog(dbConnectDialog,"DB2");
    }

    @FXML
    private void handleDbSqlServer() {
        // 处理数据库连接菜单事件
        showConnectDialog(dbConnectDialog,"SQL Server");
    }

    @FXML
    private void handleDbOracle() {
        // 处理数据库连接菜单事件
        showConnectDialog(dbConnectDialog,"Oracle");
    }
    @FXML
    private void handleDbInformix() {
        // 处理数据库连接菜单事件
        showConnectDialog(dbConnectDialog,"Informix");
    }

    @FXML
    private void handleRefreshConnBtn() {
        // 处理刷新按钮事件
    }

    @FXML
    private void handleCloseConnBtn() {
        // 处理关闭按钮事件
    }

    @FXML
    private void handleDBMigration() {
        // 处理数据迁移按钮事件
        try {
            //是否tab已经存在
            ObservableList<Tab> tabs = rightTopTabPane.getTabs();
            for (Tab tab : tabs) {
                if("dbMigrationTab".equals(tab.getId())){
                    return ;
                }
            }
            //加载页面
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(dbmigrationTabPane));
            SplitPane migrationPaneRoot = fxmlLoader.load();
            controller = fxmlLoader.getController();
            controller.setParentController(this);

            Tab dbMigrationTab = new Tab();
            dbMigrationTab.setId("dbMigrationTab");
            dbMigrationTab.setText("数据迁移");
            dbMigrationTab.setContent(migrationPaneRoot);

            // 确保SplitPane随着TabPane的大小变化而调整大小
            migrationPaneRoot.minWidthProperty().bind(rightTopTabPane.widthProperty());
            migrationPaneRoot.minHeightProperty().bind(rightTopTabPane.heightProperty());

            rightTopTabPane.getTabs().add(dbMigrationTab);
            controlTabPane.getTabs().add(migrationLogTab);
            rightNavSplitPane.setDividerPositions(0.6);

            dbMigrationTab.setOnCloseRequest(e->{
                controlTabPane.getTabs().remove(migrationLogTab);
            });

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @FXML
    private void handleSqlImport(){
        // 数据导入事件
    }

    @FXML
    private void handleSqlExport(){
        // 数据导出
    }

    @FXML
    private void handleSqlControlBtn() {
        // 处理SQL控制台按钮事件
    }

    @FXML
    private void handleSearchBtn() {
        // 处理搜索按钮事件
    }

    private void showConnectDialog(String fxmlFile,String driverType){
        // 处理数据库连接菜单事件
        try {
            FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(fxmlFile));
            Parent dialogRoot = fxmlLoader.load();
            if(fxmlLoader.getController() instanceof MenuDBConnectDialog){
                MenuDBConnectDialog menuDBConnectDialog = fxmlLoader.getController();
                menuDBConnectDialog.setDbConnectListener(this);
            }
            if(fxmlLoader.getController() instanceof BaseDBConnectDialog){
                BaseDBConnectDialog baseDBConnectDialog = fxmlLoader.getController();
                baseDBConnectDialog.getDbTypeComboBox().setValue(driverType);
                switch (driverType){
                    case "MySql":
                        baseDBConnectDialog.setDbType("mysql");
                        break;
                    case "DB2":
                        baseDBConnectDialog.setDbType("db2");
                        break;
                    case "Oracle":
                        baseDBConnectDialog.setDbType("oracle");
                        break;
                    case "Informix":
                        baseDBConnectDialog.setDbType("informix-sqli");
                        break;
                    default:
                        break;
                }

                baseDBConnectDialog.setListener(this);
            }

            Dialog<ButtonType> dialog = new Dialog<>();
            dialog.setTitle("新建数据库连接");
            dialog.getDialogPane().getButtonTypes().addAll(ButtonType.CANCEL);
            Node sysCancelButton = dialog.getDialogPane().lookupButton(ButtonType.CANCEL);
            sysCancelButton.setVisible(false);

            dialog.getDialogPane().setContent(dialogRoot);
            // 设置Dialog的owner为main.fxml的窗口
            dialog.initOwner(mainContainer.getScene().getWindow());
            // 处理窗口关闭事件，点击右上角X按钮时触发
            dialog.setOnCloseRequest(event1 -> {
                dialog.close();
            });

            dialog.show();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDatabaseConnected(HwDateSource hwDateSource) {
        if(!HwUtil.isNullOrEmpty(hwDateSource)){
            logger.info("添加数据源,查询数据库列表展示在TreeView");
            try {
                DataBaseNavService dataBaseNavService = DataBaseNavService.getInstance();
                //设置数据库导航treeview信息
                TreeItem<String> databaseInfoRoot = dataBaseNavService.getDatabaseInfoList(hwDateSource);
                if(hwConnectionListMap == null){
                    hwConnectionListMap = new HashMap<>();
                }
                hwConnectionListMap.put(databaseInfoRoot.getValue(),dataBaseNavService.getHwConnectionListMap().get(databaseInfoRoot.getValue()));
                //保存数据库配置到配置文件 用于下次加载
                dataBaseNavService.saveDatabaseConfig(hwDateSource,logger);
                //数据库导航栏展示
                dataBaseListComboBox.getItems().add(databaseInfoRoot.getValue());
                databaseNavTreeView.getRoot().getChildren().add(databaseInfoRoot);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

}